home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / lib / mntlib44.zoo / mntlib / gmon.c < prev    next >
C/C++ Source or Header  |  1993-05-23  |  18KB  |  700 lines

  1. /*
  2.  * monitor(3), mcount() and profil(2) clones for gcc-Tos library
  3.  *
  4.  * Note: these routines need tuning up. they are very space
  5.  * inefficient. the implementation is totally biased towards support
  6.  * for gprof rather than prof (does anyone use prof anymore? why?)
  7.  *
  8.  *    ++jrb    bammi@cadence.com
  9.  */
  10. #include <stddef.h>
  11. #include <memory.h>
  12. #include <unistd.h>
  13. #include <fcntl.h>
  14. #include <assert.h>
  15. #include <osbind.h>
  16. #include <basepage.h>
  17. #include <sysvars.h>
  18. #include <xbra.h>
  19. #include <string.h>
  20. #ifndef _COMPILER_H
  21. #include <compiler.h>
  22. #endif
  23.  
  24. /* gmon header */
  25. struct gm_header {
  26.     void        *low;        /* low pc  */
  27.     void        *high;        /* hi  pc  */
  28.     unsigned long    nbytes;        /* bytes in header + histo size */
  29. };
  30.  
  31. typedef unsigned short CHUNK; /* type of each histogram entry */
  32.  
  33. struct gm_call {    /* gm call record */
  34.     void    *from;    /* the caller                 */
  35.     void    *to;    /* the called function (callee)        */
  36.     unsigned long ncalls; /* # of calls from FROM to  TO    */
  37. };
  38.  
  39. #define    GMON_FILE    "gmon.out"    /* name of GMON file */
  40.  
  41. /* format of gmon file
  42.  *    gm_header
  43.  *    ((gm_header.nbytes - sizeof(gm_header))/sizeof(CHUNK)) histo entries
  44.  *    gm_call records upto EOF
  45.  */
  46.  
  47.  
  48. /* histogram variables and defines */
  49. #define    HIST_SCALE    2 /* text space scaled into size/HIST_SCALE  CHUNKS */
  50. #define HIST_SHIFT    1 /* HIST_SCALE == 2 ** HIST_SHIFT (assumption) */
  51.               /* 1 <= HIST_SHIFT <= 8          (assumption) */
  52.  
  53. static CHUNK *hist_buffer;    /* histogram buffer */
  54. static unsigned long hist_size; /* size of histogram in bytes */
  55.  
  56. /* call graph variables and defines */
  57. typedef struct  {    /* a to chain element */
  58.     void    *selfpc;    /* the callee's pc */
  59.     unsigned long count;    /* number of times called */
  60.     unsigned short link;    /* link to next in chain (an index) */
  61. } tostruct ;
  62.  
  63. tostruct       *tos;        /* pool of to chain elements */
  64. unsigned short *froms;        /* called from hash chain heads (an index) */
  65.  /* inherent assumption: typeof froms == typeof CHUNK, otherwise
  66.     change code in monstartup() */
  67.  
  68. #define MINARCS    64        /* min # of to's, a rand() # */
  69. #define ARCDENSITY 2        /* scaling of to's (as a % of  textsize) */
  70. #define HASHFRACTION 1        /* scaling of froms over textsize. 
  71.                    note this is very memory wasteful,
  72.                    but the alternatives are worse 
  73.                    beacuse of two reasons:
  74.                    - increase compute requirements(in mcount)
  75.                    - bsr, followed by bsr will loose!
  76.                    the coding of mcount below almost
  77.                    assumes that HASHFRACTION==1
  78.                    anyone else have some brilliant ideas?
  79.                    */
  80. #define HASH_SHIFT 0    /* HASHFRACTION = 2 ** HASH_SHIFT (assumption) */
  81.  
  82. /* housekeeping variables */
  83. static long          profiling;    /* profiling flag */
  84. static unsigned long  textsize;        /* size of profiled text area */
  85. static unsigned short tolimit;        /* max to == 65534, min == MINARCS */
  86. static unsigned short toalloc;        /* next free to record index  */
  87. static void           *s_lowpc;        /* low  pc rounded down to multiples
  88.                        of histo density =
  89.                        (CHUNK size * HIST_SCALE)
  90.                        (assumption: its mult of 2)
  91.                      */
  92.  
  93. #define USL(X)    ((unsigned long)(X))    /* cast X to unsigned long */
  94.  
  95. /* round X down to last multiple of Y */ /* see assumption above */
  96. #define ROUNDDOWN(X,Y)    ( USL(X) & (~(USL((Y)-1))) ) 
  97.  
  98. /* round X up to next multiple of Y */
  99. #define ROUNDUP(X,Y)    ( USL((X)+((Y)-1)) & (~(USL((Y)-1))) )
  100.  
  101. /* functions */
  102. __EXTERN void monstartup __PROTO((void *lowpc, void *highpc));
  103. __EXTERN void monitor __PROTO((void *lowpc, void *highpc, void *buffer,
  104.          unsigned long bufsize,  unsigned int nfunc));
  105. __EXTERN void moncontrol __PROTO((long flag));
  106. __EXTERN void _mcleanup __PROTO((void));
  107. __EXTERN int profil __PROTO((void *buff, unsigned long bufsiz, unsigned long offset,
  108.            int shift));
  109. /* static */ void tick __PROTO((void));
  110. static void term __PROTO((void));
  111. static void install_handlers __PROTO((void));
  112. static void remove_handlers __PROTO((void));
  113. static void unlink_handler __PROTO((xbra_struct *me, int exc));
  114. static void build_graph __PROTO((void *caller, void *callee));
  115.  
  116. /*
  117.  * allocate space for histogram and call graph given the sampling
  118.  * range. call monitor to start up profiling.
  119.  */
  120.  
  121. void monstartup(lowpc, highpc)
  122. void *lowpc, *highpc;
  123. {
  124.     unsigned long    monsize; /* size of hist buffer + gm_header rounded */
  125.     void        *buf;    /* hist + gm_header space */
  126.     unsigned long    i;
  127.  
  128.     assert(USL(lowpc) < USL(highpc));
  129.  
  130. #if 0    /* dont define: screws up gmon because of reloc assumptions */
  131.     s_lowpc = lowpc = (void *)
  132.     (ROUNDDOWN(USL(lowpc), sizeof(CHUNK)<<HIST_SHIFT ));
  133. #else
  134.     s_lowpc = lowpc;
  135. #endif
  136.     highpc = (void *)
  137.     (ROUNDUP(USL(highpc), sizeof(CHUNK)<<HIST_SHIFT ));
  138.     textsize = USL(highpc) - USL(lowpc);
  139.  
  140.     /* allocate histogram buffer + gm_header buffer */
  141.     monsize = (textsize >> HIST_SHIFT) * sizeof(CHUNK) +
  142.            sizeof(struct gm_header);
  143.     monsize = ROUNDUP(monsize, sizeof(short));
  144.  
  145.     if((buf = (CHUNK *)malloc(monsize)) == (CHUNK *)0)
  146.     {
  147.     Cconws("monitor: No memory for histogram buffer\r\n");
  148.     froms = (unsigned short *)0;
  149.     tos = (tostruct *)0;
  150.  
  151.     return;
  152.     }
  153.     bzero(buf, monsize);
  154.  
  155.     /* allocate space for graph data structs */
  156.     i = (textsize>>HASH_SHIFT) * sizeof(*froms);
  157.     i = ROUNDUP(i, sizeof(long));
  158.     if((froms = (unsigned short *)malloc(i)) == (unsigned short *)0)
  159.     {
  160.     Cconws("monitor: No memory for FROMs\r\n");
  161.     free(buf);
  162.     tos = (tostruct *)0;
  163.     return;
  164.     }
  165.     bzero(froms, i);
  166.     
  167.     i = textsize * ARCDENSITY / 100;
  168.     if( i < MINARCS)
  169.     i = MINARCS;
  170.     else if ( i > 65534)
  171.     i = 65534;
  172.     tolimit = (unsigned short)i;
  173.     i = ROUNDUP(i*sizeof(tostruct), sizeof(long));
  174.     if((tos = (tostruct *)malloc(i)) == (tostruct *)0)
  175.     {
  176.     Cconws("monitor: No memory for TOs pool\r\n");
  177.     free(froms);
  178.     free(buf);
  179.     froms = (unsigned short *)0;
  180.     return;
  181.     }
  182.     bzero(tos, i);
  183.     toalloc = 0;    /* index of next available element in TOs pool */
  184.  
  185.     monitor(lowpc, highpc, buf, monsize, (unsigned int)tolimit);
  186. }
  187.  
  188.     
  189. /*
  190.  * monitor(3) interface to profil(2)
  191.  * last arg is silly and not used
  192.  */
  193. void monitor(lowpc, highpc, buffer, bufsize, nfunc)
  194. void *lowpc, *highpc, *buffer;
  195. unsigned long bufsize;
  196. unsigned int nfunc;
  197. {
  198.     struct gm_header *hdr;
  199.  
  200.     if(lowpc == 0)
  201.     { /* finished */
  202.         moncontrol(0L);
  203.         _mcleanup();
  204.         return;
  205.     }
  206.  
  207.     s_lowpc = lowpc;    /* in case user is calling */
  208.     /* initialize gm_header */
  209.     hdr = (struct gm_header *)buffer;
  210.     hdr->low = lowpc;
  211.     hdr->high = highpc;
  212.     hdr->nbytes = bufsize;
  213.  
  214.     hist_size = bufsize - sizeof(struct gm_header); /* sizof hist buffer */
  215.     hist_buffer = (CHUNK *)(USL(buffer) + sizeof(struct gm_header));
  216.  
  217.     /* integ. check, (user can call monitor) */
  218.     if((hist_size == 0) ||
  219.            (hist_size <
  220.         (((USL(highpc) - USL(lowpc))>>HIST_SHIFT)*sizeof(CHUNK))) )
  221.     {
  222.         return;
  223.     }
  224.     /* note: difference in scaling semantics from unix */
  225.     moncontrol(1L); /* begin */
  226. }
  227.  
  228. /*
  229.  * control profiling
  230.  */
  231. void moncontrol(flag)
  232. long flag;
  233. {
  234.     if(flag)
  235.     { /* start */
  236.     profil(hist_buffer, hist_size, (unsigned long)s_lowpc, HIST_SHIFT);
  237.     profiling = 0;
  238.     }
  239.     else
  240.     {
  241.     /* stop */
  242.     profil((void *)0, 0L, 0L, 0);
  243.     profiling = 3;
  244.     }
  245. }
  246.  
  247. /*
  248.  * mcount
  249.  *    called as a part of the entry prologue of a profiled function.
  250.  *    the function that calls mcount is the CALLEE, and the function
  251.  *    that called the CALLEE is the CALLER. mcount grabs the
  252.  *    address of the CALLEE and the address of the CALLER off the
  253.  *    stack, and then calls build_graph that incrementally
  254.  *     constructs the call graphs in the FROMs and TOs structures,
  255.  *    keeping track of the number of times the CALLER called CALLEE.
  256.  *    on entry the stack look like:
  257.  *
  258.  *        sp-> |    ret address of CALLEE    |
  259.  *             |--------------------------|
  260.  *             .  CALLEE's locals        .
  261.  *             .__________________________.
  262.  * CALLEEs    fp-> |  CALLERS saved fp    |
  263.  *             |--------------------------|
  264.  *             |  ret address of CALLER    |
  265.  *             |--------------------------|
  266.  *
  267.  * Note: 
  268.  *    -this is true becuase -fomit-frame-pointer and -pg are
  269.  *     incompatible flags (gcc will say so if you try)
  270.  *
  271.  *    -on the 68k, the address of a long count location is passed in a0
  272.  *     we dont use this, it was a convention for the old prof stuff.
  273.  */
  274.  
  275. #if __GNUC__ > 1
  276. void mcount (void